/**
 *  This file is part of PennerBot
 *
 *  Copyright (C) 2010 microkernel
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define PBOT_SPECIAL
#ifdef PBOT_SPECIAL

#include <core/convert.hpp>
#include <core/messages.hpp>
#include <core/portable.hpp>
#include <core/regex.hpp>

#include <core/modules/autoskill.hpp>


namespace PBot
{
namespace Core
{

AutoSkill::AutoSkill(Connection& _con, Config* _cfg)
 : Module(_con, _cfg), paused(false), antiCaptcha(AntiCaptcha::GetInstance()), current(0), failedAttempts(0)
{
    moduleName = "AutoSkill";
}

AutoSkill::~AutoSkill()
{
}

bool AutoSkill::Do()
{
    if(!cfg->AS_enabled && !paused)
    {
        listener.Dispatch(cfg->id, MSG_AS_DISABLED);
        paused = true;
        return true;
    }
    else if(!cfg->AS_enabled && paused)
    {
        return true;
    }
    else if(cfg->AS_enabled && paused)
    {
        listener.Dispatch(cfg->id, MSG_AS_ENABLED);
        paused = false;
    }

    if(cfg->skills.size() == 0)
    {
        listener.Dispatch(cfg->id, MSG_AS_NOSKILLS);
        paused = true;
        return true;
    }
/*
    // Load overview -> stock
    std::string url = cfg->website + "/overview/";
    if(!con.Get(url))
    {
        ++failedAttempts;
        continue;
    }

    PortableSleep(1,3);

    url = cfg->website + "/stock/";
    if(!con.Get(url))
    {
        ++failedAttempts;
        continue;
    }
    PortableSleep(1,3);

    url = cfg->website + "/stock/foodstuffs/use/";
    if(!con.Post(url, "item=Bier&promille=35&id=1&menge=8"))
    {
        ++failedAttempts;
        continue;
    }
*/

    while(failedAttempts < MAX_AS_ATTEMPTS)
    {
        if(current >= cfg->skills.size())
        {
            current = 0;
        }

        // Load overview -> activities -> skills
        std::string url = cfg->website + "/overview/";
        if(!con.Get(url))
        {
            ++failedAttempts;
            continue;
        }

        PortableSleep(1,3);

        url = cfg->website + "/activities/";
        if(!con.Get(url))
        {
            ++failedAttempts;
            continue;
        }

        PortableSleep(1,3);

        url = cfg->website + "/skills/";
        if(!con.Get(url))
        {
            ++failedAttempts;
            continue;
        }

        Strings::String skillString = static_cast<Strings::String>(cfg->skills[current] + Strings::AS_ATT);
        size_t pos1 = con.GetBuffer().find(std::string("id=\"") + str.GetString(cfg->game, skillString));
        size_t pos2 = con.GetBuffer().find("disabled", pos1);

        if(cfg->hasCaptcha)
        {
           // Get captcha url (same as in BottleCollect)
           if(!str.GetRegex(cfg->game, Strings::BC_CAPTCHAURL)->Search(con.GetBuffer(), url))
           {
               listener.Dispatch(cfg->id, MSG_AS_CAPTCHACHD);
               ++failedAttempts;
               continue;
           }
        }

        int skillcounter;
        if(!str.GetRegex(cfg->game, Strings::AS_SKILLCOUNTER)->Search(con.GetBuffer(), skillcounter))
        {
            listener.Dispatch(cfg->id, MSG_AS_SKILLCOUNTERFAIL);
            ++failedAttempts;
            continue;
        }

        if(skillcounter >= 0)
        {
            listener.Dispatch(cfg->id, MSG_AS_ALREADYEDUCATING, Sleep(skillcounter+10, skillcounter+30));
            failedAttempts = 0;
            return true;
        }
        else if(pos2 != std::string::npos && pos2-pos1 < 100)
        {
            listener.Dispatch(cfg->id, MSG_AS_DEPENDENCY, str.GetString(cfg->game, skillString));
        }
        else
        {
            listener.Dispatch(cfg->id, MSG_AS_TRYING, str.GetString(cfg->game, skillString));

            url = cfg->website + "/skill/upgrade/" + str.GetString(cfg->game, skillString) + "/";

            if(cfg->hasCaptcha)
            {
                // Download captcha
                std::string filename = "captchas/captcha_as_"+cfg->botname+".jpg";

                // Get captcha url
                if(!str.GetRegex(cfg->game, Strings::BC_CAPTCHAURL)->Search(con.GetBuffer(), url))
                {
                    listener.Dispatch(cfg->id, MSG_BC_CAPTCHACHD);
                    ++failedAttempts;
                    continue;
                }

                if(!con.GetFile(url, filename, false))
                {
                    ++failedAttempts;
                    continue;
                }


                int x,y;
                std::string postdata;

                switch(antiCaptcha.Crack(filename, x, y))
                {
                    case AntiCaptcha::CRACKFAIL:
                        listener.Dispatch(cfg->id, MSG_AC_CRACKFAIL);
                        ++failedAttempts;
                        continue;

                    case AntiCaptcha::IOERROR:
                        listener.Dispatch(cfg->id, MSG_AC_IOERROR, filename);
                        ++failedAttempts;
                        continue;

                    case AntiCaptcha::CRACKOKAY:
                        postdata = "captchacheck.x=" + NumToStr(x) + "&captchacheck.y=" + NumToStr(y);

                        // set url (changed while getting captcha)
                        url = cfg->website + "/skill/upgrade/" + str.GetString(cfg->game, skillString) + "/";

                        if(!con.Post(url, postdata))
                        {
                            ++failedAttempts;
                            continue;
                        }

                        if(!str.GetRegex(cfg->game, Strings::AS_SKILLCOUNTER)->Search(con.GetBuffer(), skillcounter))
                        {
                            listener.Dispatch(cfg->id, MSG_AS_SKILLCOUNTERFAIL);
                            ++failedAttempts;
                            continue;
                        }

                        if(skillcounter >= 0)
                        {
                            listener.Dispatch(cfg->id, MSG_AS_STARTED, Sleep(skillcounter+10, skillcounter+30));
                            failedAttempts = 0;
                             ++current;

                            return true;
                        }
                        else
                        {
                            listener.Dispatch(cfg->id, MSG_AC_CRACKFAIL);
                            ++failedAttempts;
                            continue;
                        }

                        break;
                }

            }
            else
            {
                if(!con.Post(url, ""))
                {
                    ++failedAttempts;
                    continue;
                }

                if(!str.GetRegex(cfg->game, Strings::AS_SKILLCOUNTER)->Search(con.GetBuffer(), skillcounter))
                {
                    listener.Dispatch(cfg->id, MSG_AS_SKILLCOUNTERFAIL);
                    ++failedAttempts;
                    continue;
                }

                if(skillcounter >= 0)
                {
                    listener.Dispatch(cfg->id, MSG_AS_STARTED, Sleep(skillcounter+10, skillcounter+30));
                    failedAttempts = 0;
                     ++current;

                    return true;
                }
            }


        }



        Sleep(30, 120);
        ++current;

        return true;
    }

    listener.Dispatch(cfg->id, MSG_AS_TOOMANYATTEMPTS);
    failedAttempts = 0;

    Sleep(10*60);

    return true;
}


}
}

#endif /* PBOT_SPECIAL */
